<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Color 4: Resolving color values</title>
<link rel="author" title="Chris Nardi" href="mailto:csnardi1@gmail.com">
<link rel="help" href="https://drafts.csswg.org/css-color-4/#resolving-color-values">
<meta name="assert" content="Tests if color values are resolved properly">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>

<div id="parent" style="color: rgb(45, 23, 27)">
    <div id="inner"></div>
</div>

<script>
    function color_test(color, expected, reason) {
        test(function() {
            var element = document.getElementById('inner');
            // Random value not in our test data.
            fail_value = "rgb(12, 34, 223)"
            element.style.color = "black";
            element.style.cssText = "color: " + fail_value + "; color: " + color;

            if (expected === null)
                assert_equals(getComputedStyle(element).color, fail_value);
            else
                assert_equals(getComputedStyle(element).color, expected);
        }, `${reason}: ${color}`);
    }

    function expected_value(rgb_channels) {
        if (rgb_channels === null)
            return null;
        else if (rgb_channels.length === 3 || rgb_channels[3] == 1)
            return "rgb(" + rgb_channels.slice(0, 3).join(", ") + ")";
        else
            return "rgba(" + rgb_channels.join(", ") + ")";
    }

    tests = [
        // Keyword tests
        ["", null, "Should not parse invalid keyword"],
        [" /* hey */\n", null, "Should not parse invalid keyword"],
        ["4", null, "Should not parse invalid keyword"],
        ["top", null, "Should not parse invalid keyword"],
        ["/**/transparent", [0, 0, 0, 0], "Should parse to completely transparent"],
        ["transparent", [0, 0, 0, 0], "Should parse to completely transparent"],
        [" transparent\n", [0, 0, 0, 0], "Should parse to completely transparent"],
        ["TransParent", [0, 0, 0, 0], "Should parse to completely transparent"],
        ["currentColor", [45, 23, 27], "Should be same as parent color"],
        ["CURRENTcolor", [45, 23, 27], "Should be same as parent color"],
        ["current-Color", null, "Should not parse invalid keyword"],
        ["black", [0, 0, 0, 1], "Should parse as correct value"],
        ["white", [255, 255, 255, 1], "Should parse as correct value"],
        ["fuchsia", [255, 0, 255, 1], "Should parse as correct value"],
        ["cyan", [0, 255, 255, 1], "Should parse as correct value"],
        ["CyAn", [0, 255, 255, 1], "Should parse as cyan"],

        // Hex tests
        ["#", null, "Should not parse invalid hex"],
        ["#f", null, "Should not parse invalid hex"],
        ["#ff", null, "Should not parse invalid hex"],
        ["#fff", [255, 255, 255, 1], "Valid 3-digit hex"],
        ["#ffg", null, "Should not parse invalid hex"],
        ["#ffff", [255, 255, 255, 1], "Valid 4-digit hex"],
        ["#fffg", null, "Should not parse invalid hex"],
        ["#fffff", null, "Should not parse invalid hex"],
        ["#ffffff", [255, 255, 255, 1], "Valid 6-digit hex"],
        ["#fffffg", null, "Should not parse invalid hex"],
        ["#fffffff", null, "Should not parse invalid hex"],
        ["#ffffffff", [255, 255, 255, 1], "Valid 8-digit hex"],
        ["#fffffffg", null, "Should not parse invalid hex"],
        ["#fffffffff", null, "Should not parse invalid hex"],
        ["#FFCc99", [255, 204, 153, 1], "Valid 6-digit hex"],
        ["#369", [51, 102, 153, 1], "Valid 3-digit hex"],

        // RGB tests
        ["rgb(00, 51, 102)", [0, 51, 102, 1], "Valid numbers should be parsed"],
        ["r\\gb(00, 51, 102)", [0, 51, 102, 1], "Correct escape sequences should still parse"],
        ["r\\67 b(00, 51, 102)", [0, 51, 102, 1], "Correct escape sequences should still parse"],
        ["RGB(153, 204, 255)", [153, 204, 255, 1], "Capitalization should not affect parsing"],
        ["rgB(0, 0, 0)", [0, 0, 0, 1], "Capitalization should not affect parsing"],
        ["rgB(0, 51, 255)", [0, 51, 255, 1], "Capitalization should not affect parsing"],
        ["rgb(0,51,255)", [0, 51, 255, 1], "Lack of whitespace should not affect parsing"],
        ["rgb(0\t,  51 ,255)", [0, 51, 255, 1], "Whitespace should not affect parsing"],
        ["rgb(/* R */0, /* G */51, /* B */255)", [0, 51, 255, 1], "Comments should be allowed within function"],
        ["rgb(-51, 306, 0)", [0, 255, 0, 1], "Invalid values should be clamped to 0 and 255 respectively"],
        ["rgb(42%, 3%, 50%)", [107, 8, 128, 1], "Valid percentages should be parsed"],
        ["RGB(100%, 100%, 100%)", [255, 255, 255, 1], "Capitalization should not affect parsing"],
        ["rgB(0%, 0%, 0%)", [0, 0, 0, 1], "Capitalization should not affect parsing"],
        ["rgB(10%, 20%, 30%)", [26, 51, 77, 1], "Capitalization should not affect parsing"],
        ["rgb(10%,20%,30%)", [26, 51, 77, 1], "Whitespace should not affect parsing"],
        ["rgb(10%\t,  20% ,30%)", [26, 51, 77, 1], "Whitespace should not affect parsing"],
        ["rgb(/* R */ 10%, /* G */ 20%, /* B */ 30%)", [26, 51, 77, 1], "Comments should not affect parsing"],
        ["rgb(-12%, 110%, 1400%)", [0, 255, 255, 1], "Invalid values should be clamped to 0 and 255 respectively"],
        ["rgb(10%, 50%, 0)", null, "Values must be all numbers or all percentages"],
        ["rgb(255, 50%, 0%)", null, "Values must be all numbers or all percentages"],
        ["rgb(0, 0 0)", null, "Comma optional syntax requires no commas at all"],
        ["rgb(0, 0, 0deg)", null, "Angles are not accepted in the rgb function"],
        ["rgb(0, 0, light)", null, "Keywords are not accepted in the rgb function"],
        ["rgb()", null, "The rgb function requires 3 or 4 arguments"],
        ["rgb(0)", null, "The rgb function requires 3 or 4 arguments"],
        ["rgb(0, 0)", null, "The rgb function requires 3 or 4 arguments"],
        ["rgb(0%)", null, "The rgb function requires 3 or 4 arguments"],
        ["rgb(0%, 0%)", null, "The rgb function requires 3 or 4 arguments"],
        ["rgb(0, 0, 0, 0)", [0, 0, 0, 0], "RGB and RGBA are synonyms"],
        ["rgb(0%, 0%, 0%, 0%)", [0, 0, 0, 0], "RGB and RGBA are synonyms"],
        ["rgb(0%, 0%, 0%, 0)", [0, 0, 0, 0], "RGB and RGBA are synonyms"],
        ["rgba(0, 0, 0, 0)", [0, 0, 0, 0], "Valid numbers should be parsed"],
        ["rgba(204, 0, 102, 0.3)", [204, 0, 102, 0.3], "Valid numbers should be parsed"],
        ["RGBA(255, 255, 255, 0)", [255, 255, 255, 0], "Capitalization should not affect parsing"],
        ["rgBA(0, 51, 255, 1)", [0, 51, 255, 1], "Capitalization should not affect parsing"],
        ["rgba(0, 51, 255, 1.1)", [0, 51, 255, 1], "Invalid alpha values should be clamped to 0 and 1 respectively"],
        ["rgba(0, 51, 255, 37)", [0, 51, 255, 1], "Invalid alpha values should be clamped to 0 and 1 respectively"],
        ["rgba(0, 51, 255, 0.42)", [0, 51, 255, 0.42], "Valid numbers should be parsed"],
        ["rgba(0, 51, 255, 0)", [0, 51, 255, 0], "Valid numbers should be parsed"],
        ["rgba(0, 51, 255, -0.1)", [0, 51, 255, 0], "Invalid alpha values should be clamped to 0 and 1 respectively"],
        ["rgba(0, 51, 255, -139)", [0, 51, 255, 0], "Invalid alpha values should be clamped to 0 and 1 respectively"],
        ["RGBA(100%, 100%, 100%, 0)", [255, 255, 255, 0], "Capitalization should not affect parsing"],
        ["rgba(42%, 3%, 50%, 0.3)", [107, 8, 128, 0.3], "Valid percentages should be parsed"],
        ["rgBA(0%, 20%, 100%, 1)", [0, 51, 255, 1], "Capitalization should not affect parsing"],
        ["rgba(0%, 20%, 100%, 1.1)", [0, 51, 255, 1], "Invalid alpha values should be clamped to 0 and 1 respectively"],
        ["rgba(0%, 20%, 100%, 37)", [0, 51, 255, 1], "Invalid alpha values should be clamped to 0 and 1 respectively"],
        ["rgba(0%, 20%, 100%, 0.42)", [0, 51, 255, 0.42], "Valid percentages should be parsed"],
        ["rgba(0%, 20%, 100%, 0)", [0, 51, 255, 0], "Valid percentages should be parsed"],
        ["rgba(0%, 20%, 100%, -0.1)", [0, 51, 255, 0], "Invalid alpha values should be clamped to 0 and 1 respectively"],
        ["rgba(0%, 20%, 100%, -139)", [0, 51, 255, 0], "Invalid alpha values should be clamped to 0 and 1 respectively"],
        ["rgba(255, 255, 255, 0%)", [255, 255, 255, 0], "Percent alpha values are accepted in rgb/rgba"],
        ["rgba(0%, 0%, 0%, 0%)", [0, 0, 0, 0], "Percent alpha values are accepted in rgb/rgba"],
        ["rgba(0%, 0%, 0%)", [0, 0, 0, 1], "RGB and RGBA are synonyms"],
        ["rgba(0, 0, 0)", [0, 0, 0, 1], "RGB and RGBA are synonyms"],
        ["rgba(10%, 50%, 0, 1)", null, "Values must be all numbers or all percentages"],
        ["rgba(255, 50%, 0%, 1)", null, "Values must be all numbers or all percentages"],
        ["rgba(0, 0, 0 0)", null, "Comma optional syntax requires no commas at all"],
        ["rgba(0, 0, 0, 0deg)", null, "Angles are not accepted in the rgb function"],
        ["rgba(0, 0, 0, light)", null, "Keywords are not accepted in the rgb function"],
        ["rgba()", null, "The rgba function requires 3 or 4 arguments"],
        ["rgba(0)", null, "The rgba function requires 3 or 4 arguments"],
        ["rgba(0, 0, 0, 0, 0)", null, "The rgba function requires 3 or 4 arguments"],
        ["rgba(0%)", null, "The rgba function requires 3 or 4 arguments"],
        ["rgba(0%, 0%)", null, "The rgba function requires 3 or 4 arguments"],
        ["rgba(0%, 0%, 0%, 0%, 0%)", null, "The rgba function requires 3 or 4 arguments"],

        // HSL tests
        ["HSL(0, 0%, 0%)", [0, 0, 0, 1], "Capitalization should not affect parsing"],
        ["hsL(0, 100%, 50%)", [255, 0, 0, 1], "Capitalization should not affect parsing"],
        ["hsl(60, 100%, 37.5%)", [191, 191, 0, 1], "Valid numbers should be parsed"],
        ["hsl(780, 100%, 37.5%)", [191, 191, 0, 1], "Angles are represented as a part of a circle and wrap around"],
        ["hsl(-300, 100%, 37.5%)", [191, 191, 0, 1], "Angles are represented as a part of a circle and wrap around"],
        ["hsl(300, 50%, 50%)", [191, 64, 191, 1], "Valid numbers should be parsed"],
        ["hsl(30deg, 100%, 100%)", [255, 255, 255, 1], "Angles are accepted in HSL/HSLA"],
        ["hsl(0, 0%, 0%, 0%)", [0, 0, 0, 0], "HSL and HSLA are synonyms"],
        ["hsl(10, 50%, 0)", null, "The second and third parameters of hsl/hsla must be a percent"],
        ["hsl(50%, 50%, 0%)", null, "The first parameter of hsl/hsla must be a number or angle"],
        ["hsl(0, 0% 0%)", null, "Comma optional syntax requires no commas at all"],
        ["hsl(0, 0%, light)", null, "Keywords are not accepted in the hsl function"],
        ["hsl()", null, "The hsl function requires 3 or 4 arguments"],
        ["hsl(0)", null, "The hsl function requires 3 or 4 arguments"],
        ["hsl(0, 0%)", null, "The hsl function requires 3 or 4 arguments"],
        ["HSLA(-300, 100%, 37.5%, 1)", [191, 191, 0, 1], "Angles are represented as a part of a circle and wrap around"],
        ["hsLA(-300, 100%, 37.5%, 12)", [191, 191, 0, 1], "Invalid alpha values should be clamped to 0 and 1 respectively"],
        ["hsla(-300, 100%, 37.5%, 0.2)", [191, 191, 0, 0.2], "Angles are represented as a part of a circle and wrap around"],
        ["hsla(-300, 100%, 37.5%, 0)", [191, 191, 0, 0], "Angles are represented as a part of a circle and wrap around"],
        ["hsla(-300, 100%, 37.5%, -3)", [191, 191, 0, 0], "Invalid alpha values should be clamped to 0 and 1 respectively"],
        ["hsla(0, 0%, 0%, 50%)", [0, 0, 0, 0.5], "Percent alpha values are accepted in hsl/hsla"],
        ["hsla(30deg, 100%, 100%, 1)", [255, 255, 255, 1], "Angles are accepted in HSL/HSLA"],
        ["hsla(10, 50%, 0, 1)", null, "The second and third parameters of hsl/hsla must be a percent"],
        ["hsla(50%, 50%, 0%, 1)", null, "The first parameter of hsl/hsla must be a number or angle"],
        ["hsla(0, 0% 0%, 1)", null, "Comma optional syntax requires no commas at all"],
        ["hsla(0, 0%, light, 1)", null, "Keywords are not accepted in the hsla function"],
        ["hsla()", null, "The hsla function requires 3 or 4 arguments"],
        ["hsla(0)", null, "The hsla function requires 3 or 4 arguments"],
        ["hsla(0, 0%)", null, "The hsla function requires 3 or 4 arguments"],
        ["hsla(0, 0%, 0%, 1, 0%)", null, "The hsla function requires 3 or 4 arguments"]
    ]

    for (var value in tests) {
        items_to_test = tests[value];
        color_test(items_to_test[0], expected_value(items_to_test[1]), items_to_test[2]);
    }
</script>
